﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using IRCServer.Entities.Commands;
using IRCServer.Entities;
using IRCServer.Backend;
using IRC.Utilities;
using System.Threading;

namespace IRCServer.CommandHandlers
{
    class SPRIVMSGCommandHandler : CommandHandlerBase
    {
        public override string HandleCommand(global::IRCServer.Entities.Commands.IRCCommandBase command, global::IRCServer.Entities.SessionBase session)
        {
            if (command is SPRIVMSGCommand)
            {
                SPRIVMSGCommand sPrivmsgCommand = (SPRIVMSGCommand)command;
                // In case it is forwarded from a fellow server, check if it is a msg to a local user
                List<User> filteredUsers = ServerBackend.Instance.Users.Where(u => u.Nickname.ToLower() == sPrivmsgCommand.Target.ToLower()).ToList();
                if (filteredUsers.Count != 0)
                {
                    ClientSession clientSession = ServerBackend.Instance.GetClientSessionByNickname(filteredUsers[0].Nickname);

                    PRIVMSGCommand privmsgCommand = new PRIVMSGCommand(string.Format("{0} {1} :{2}", "PRIVMSG", sPrivmsgCommand.Target, sPrivmsgCommand.Message));
                    return privmsgCommand.ExecuteCommand(clientSession);
                }

                Thread thread = new Thread(new ParameterizedThreadStart(ForwardMessage));
                thread.Start(sPrivmsgCommand);             

                return string.Empty;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        private void ForwardMessage(object command)
        {
            SPRIVMSGCommand sPrivmsgCommand = (SPRIVMSGCommand)command;

            Logger.Instance.Debug(string.Format("[SPRIVMSG] forwarding message"));
            // Message should be sent to a fellow server.
            string routerCommand = Entities.RoutingDaemon.GetCommandName(global::IRCServer.Entities.RoutingDaemonCommands.NEXTHOP, new string[] { sPrivmsgCommand.Target });
            string response = Backend.ServerBackend.Instance.RoutingDaemon.SendCommand(routerCommand);
            Logger.Instance.Debug(string.Format("[SPRIVMSG] Response is '{0}'", response));
            string[] responseParts = response.Split(' ');
            switch (responseParts.Length)
            {
                case 1:
                    {
                        if (responseParts[0] == Entities.RoutingDaemon.GetResponseName(global::IRCServer.Entities.RoutingDaemonResponses.NONE))
                        {
                            //cannot deliver message
                            return;
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                    }
                case 3:
                    {
                        if (responseParts[0] == Entities.RoutingDaemon.GetResponseName(global::IRCServer.Entities.RoutingDaemonResponses.OK))
                        {
                            int nodeId = int.Parse(responseParts[1]);
                            int distance = int.Parse(responseParts[2]);
                            List<ServerSession> serverSessions = Backend.ServerBackend.Instance.ServerSessions.Where(s => s.ServerNodeID == nodeId).ToList();
                            if (serverSessions.Count == 0)
                            {
                                // Cannot find the server, Drop the message.
                                return;
                            }
                            else
                            {
                                if (serverSessions.Count > 1)
                                {
                                    throw new InvalidOperationException();
                                }
                                else
                                {
                                    //Forward the message to that server.
                                    Logger.Instance.Debug(string.Format("[SPRIVMSG] Forwarding to '{0}'", response));
                                    serverSessions[0].Socket.Send(ASCIIEncoding.ASCII.GetBytes(sPrivmsgCommand.CommandText));
                                    return;
                                }
                            }
                        }
                        else
                        {
                            throw new InvalidOperationException();
                        }
                    }
                default:
                    {
                        throw new InvalidOperationException();
                    }

            }
        }
    }
}
